package org.tim.websocket.chat;

import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.tim.common.msg.ChatType;
import org.tim.common.msg.TimMessage;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.core.TioConfig;
import org.tio.websocket.common.WsRequest;
import org.tio.websocket.common.WsResponse;

import java.util.ArrayList;

@Slf4j
public class DefaultPrivateChatKit implements ChatKit {
    @Autowired
    private TioConfig tioConfig;

    @Autowired
    private ConfigurableApplicationContext applicationContext;

    private final Gson gson = new GsonBuilder().create();

    @Override
    public boolean isSupport(TimMessage timMessage) {
        return ChatType.PRIVATE.equals(timMessage.getChatType());
    }

    @Override
    public void chat(WsRequest wsRequest, TimMessage message, ChannelContext channelContext, Promise<TimMessage> promise) {
        chat(
                WsResponse.fromText(gson.toJson(message), "utf-8"),
                message,
                channelContext,
                promise
        );
    }

    private void chat(WsResponse wsResponse, TimMessage timMessage, ChannelContext channelContext, Promise<TimMessage> promise) {
        var beforeChatKitIterator = getBeforeChatKitAspects().stream().filter(beforeChatKit -> {
            return beforeChatKit.isSupport(timMessage);
        }).iterator();

        while (beforeChatKitIterator.hasNext()) {
            var next = beforeChatKitIterator.next();
            next.beforeChat(wsResponse, timMessage, channelContext, promise);
        }

        if(promise.isDone()) return;

        doChat(timMessage, channelContext, promise);
    }

    private void doChat(TimMessage message, ChannelContext channelContext, Promise<TimMessage> promise) {
        synchronized (this) {
            if (isOnline(message.getToUserId())) {

                var isSuccess = Tio.sendToUser(
                        channelContext.tioConfig,
                        message.getToUserId(),
                        WsResponse.fromText(gson.toJson(message), "utf-8"));

                if (isSuccess) {
                    promise.setSuccess(message);
                } else {
                    promise.setFailure(new Throwable("Send msg fail"));
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("User {} offline, msg has saved", message.getToUserId());
                }

                promise.setSuccess(message);
            }
        }
    }

    /**
     * 判断发送的对方用户是否在线
     *
     * @param userId 用户ID
     * @return
     */
    public boolean isOnline(String userId) {
        var setWithLock = tioConfig.users.find(tioConfig, userId);
        return setWithLock != null && setWithLock.size() > 0;
    }

    private ArrayList<BeforeChatKit> getBeforeChatKitAspects() {
        var list = Lists.newArrayList(applicationContext.getBeanFactory().getBeanProvider(BeforeChatKit.class));
        AnnotationAwareOrderComparator.sort(list);
        return list;
    }
}
